from flask import Flask, jsonify
from sqlalchemy import func, desc
from flask_sqlalchemy import SQLAlchemy
from models import candidates, constituencies, parties, votes, results
from app import UK2019ElecDatabase
from collections import defaultdict
from sqlalchemy.orm import joinedload

def fetch_data():
    session = UK2019ElecDatabase.create_scoped_session()
    candidates_data = session.query(candidates).options(joinedload(candidates.constituency)).all()
    constituencies_data = session.query(constituencies).all()
    votes_data = session.query(votes).options(joinedload(votes.party), joinedload(votes.constituency)).all()
    parties_data = session.query(parties).all()
    session.close()
    return votes_data, parties_data, candidates_data, constituencies_data
def calculate_seats_based_on_constituencies(votes_data):
  # Debugged using phind
  # Define the total number of seats
  totalSeats = 650 # Total number of seats in the UK parliament

  # Group votes by constituency name and party name
  votesByConstituency = defaultdict(lambda: defaultdict(list))
  for vote in votes_data:
      votesByConstituency[constituencies.query.get(vote.constituency_id).constituency_name][parties.query.get(vote.party_id).party_name].append(vote)

  # Calculate the number of votes each party got in each constituency
  votesPerPartyPerConstituency = defaultdict(int)
  for constituency_name, votesByParty in votesByConstituency.items():
      for party_name, votes in votesByParty.items():
          votesPerPartyPerConstituency[(constituency_name, party_name)] += sum(vote.votes for vote in votes)

  # Find the party that got the most votes in each constituency
  mostVotesPerConstituency = {}
  for (constituency_name, party_name), votes in votesPerPartyPerConstituency.items():
      if constituency_name not in mostVotesPerConstituency or votes > mostVotesPerConstituency[constituency_name][1]:
          mostVotesPerConstituency[constituency_name] = (party_name, votes)

  # Count the number of seats each party won
  seatsWon = defaultdict(int)
  for constituency_name, (party_name, _) in mostVotesPerConstituency.items():
      if totalSeats > 0:
          seatsWon[party_name] += 1
          totalSeats -= 1
      else:
          break

  # Return the number of seats won by each party
  return dict(seatsWon)
def fptp_results(votes_data):
  # Debugged using phind
  # Initialise dictionaries to count the seats won by each party and the total votes for each party
  partySeatCount = {}
  partyTotalVotes = {}
  # Use the pre-determined seats
  seatsWon = calculate_seats_based_on_constituencies(votes_data)
  # Iterate over the pre-determined seats
  for party_name, seats in seatsWon.items():
      # Update the seat count for the party
      partySeatCount[party_name] = seats
  # Prepare the result list
  result = []
  # Calculate the total seats won by all parties
  totalSeats = 650
  # Sort parties by the number of seats in descending order
  sortedParties = sorted(partySeatCount.items(), key=lambda x: x[1], reverse=True)
  # Limit the result to the top 12 parties
  for party_name, seats in sortedParties[:12]:
      # Calculate the percentage of seats won
      percentageSeats = (seats / totalSeats) * 100
      # Calculate the total votes for the party
      partyTotalVotes[party_name] = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
      # Calculate the percentage of popular votes
      percentagePopularVotes = (partyTotalVotes[party_name] / sum(vote.votes for vote in votes_data)) * 100
      # Calculate the difference percentage
      differencePercentage = abs((percentagePopularVotes - percentageSeats) / percentageSeats) * 100
      data_entry = {
          "system1": "FPTP",
          "party": party_name,
          "seat_allocation": seats,
          "percentage_of_seats": round(percentageSeats, 2),
          "percentage_of_popular_votes": round(percentagePopularVotes, 2),
          "difference_percentage": round(differencePercentage, 2),
          "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
          "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
      }
      result1 = results(system1="FPTP", 
                       party = party_name, 
                       seat_allocation = seats,
                       percentage_of_seats = round(percentageSeats, 2),
                       percentage_of_popular_votes = round(percentagePopularVotes, 2),
                       difference_percentage = round(differencePercentage, 2), 
                       winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                       different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
      UK2019ElecDatabase.session.add(result1)
      UK2019ElecDatabase.session.commit()
      result.append(data_entry)
  return result

def proportional_representation(votes_data):
  # Debugged using phind
  # Define the total number of seats
  totalSeats = 650 # Total number of seats in the UK parliament
  # Group votes by party name
  votesByParty = defaultdict(list)
  for vote in votes_data:
      votesByParty[parties.query.get(vote.party_id).party_name].append(vote)
  # Calculate the total votes for each party
  partyTotalVotes = defaultdict(int)
  for party_name, votes in votesByParty.items():
      partyTotalVotes[party_name] = sum(vote.votes for vote in votes)
  # Calculate the seat allocation for each party
  partySeatCount = {}
  for party_name, votes in partyTotalVotes.items():
      partySeatCount[party_name] = round((votes / sum(partyTotalVotes.values())) * totalSeats)
  # Prepare the result list
  result = []
  # Sort parties by the number of seats in descending order
  sortedParties = sorted(partySeatCount.items(), key=lambda x: x[1], reverse=True)
  # Limit the result to the top 15 parties
  for party_name, seats in sortedParties[:15]:
      # Calculate the percentage of seats won
      percentageSeats = (seats / totalSeats) * 100
      # Calculate the total votes for the party
      partyTotalVotes = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
      # Calculate the percentage of popular votes
      percentagePopularVotes = (partyTotalVotes / sum(vote.votes for vote in votes_data)) * 100
      # Calculate the difference percentage
      differencePercentage = abs((percentagePopularVotes - percentageSeats) / percentageSeats) * 100
      data_entry = {
          "system1": "SPR",
          "party": party_name,
          "seat_allocation": seats,
          "percentage_of_seats": round(percentageSeats, 2),
          "percentage_of_popular_votes": round(percentagePopularVotes, 2),
          "difference_percentage": round(differencePercentage, 2),
          "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
          "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
      }
      result1 = results(system1="SPR", 
                       party = party_name, 
                       seat_allocation = seats,
                       percentage_of_seats = round(percentageSeats, 2),
                       percentage_of_popular_votes = round(percentagePopularVotes, 2),
                       difference_percentage = round(differencePercentage, 2), 
                       winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                       different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
      UK2019ElecDatabase.session.add(result1)
      UK2019ElecDatabase.session.commit()
      result.append(data_entry)
  return result

def proportional_representation_5threshold(votes_data):
    # Debugged using Phind
    # Define the total number of seats
    totalSeats = 650 # Total number of seats in the UK parliament
    # Define the threshold
    threshold = 0.05 # 5% threshold
    # Group votes by party name
    votesByParty = defaultdict(list)
    for vote in votes_data:
        votesByParty[parties.query.get(vote.party_id).party_name].append(vote)
    # Calculate the total votes for each party
    partyTotalVotes = defaultdict(int)
    for party_name, votes in votesByParty.items():
        partyTotalVotes[party_name] = sum(vote.votes for vote in votes)
    # Filter out parties whose total votes are less than the threshold
    filtered_parties = [(party_name, votes) for party_name, votes in partyTotalVotes.items() if votes >= threshold * sum(partyTotalVotes.values())]
    # Calculate the seat allocation for each party
    partySeatCount = {}
    for party_name, votes in filtered_parties:
        partySeatCount[party_name] = round((votes / sum(partyTotalVotes.values())) * totalSeats)
    # Prepare the result list
    result = []
    # Sort parties by the number of seats in descending order
    sortedParties = sorted(partySeatCount.items(), key=lambda x: x[1], reverse=True)
    # Limit the result to the top 3 parties
    for party_name, seats in sortedParties[:3]:
        # Calculate the percentage of seats won
        percentageSeats = (seats / totalSeats) * 100
        # Calculate the total votes for the party
        partyTotalVotes = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
        # Calculate the percentage of popular votes
        percentagePopularVotes = (partyTotalVotes / sum(vote.votes for vote in votes_data)) * 100
        # Calculate the difference percentage
        differencePercentage = abs((percentagePopularVotes - percentageSeats) / percentageSeats) * 100
        data_entry = {
            "system1": "SPR 5%",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentageSeats, 2),
            "percentage_of_popular_votes": round(percentagePopularVotes, 2),
            "difference_percentage": round(differencePercentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
        }
        result1 = results(system1="SPR 5%", 
                       party = party_name, 
                       seat_allocation = seats,
                       percentage_of_seats = round(percentageSeats, 2),
                       percentage_of_popular_votes = round(percentagePopularVotes, 2),
                       difference_percentage = round(differencePercentage, 2), 
                       winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                       different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
        result.append(data_entry)
    return result
def proportional_representation_by_county(votes_data):
    # Debugged using phind
    # Define the total number of seats
    totalSeats = 650 # Total number of seats in the UK parliament
    # Group votes by party name and constituency (county)
    votesByPartyAndCounty = defaultdict(lambda: defaultdict(list))
    for vote in votes_data:
        votesByPartyAndCounty[parties.query.get(vote.party_id).party_name][constituencies.query.get(vote.constituency_id).constituency_name].append(vote)
    # Calculate the total votes for each party in each county
    partyTotalVotesByCounty = defaultdict(lambda: defaultdict(int))
    for party_name, votes_by_county in votesByPartyAndCounty.items():
        for county_name, votes in votes_by_county.items():
            partyTotalVotesByCounty[party_name][county_name] = sum(vote.votes for vote in votes)
    # Calculate the seat allocation for each party in each county
    partySeatCountByCounty = {}
    for party_name, votes_by_county in partyTotalVotesByCounty.items():
        for county_name, votes in votes_by_county.items():
            partySeatCountByCounty[(party_name, county_name)] = round((votes / sum(votes_by_county.values())) * totalSeats)
    # Prepare the result list
    result = []
    # Sort parties by the number of seats in descending order
    sortedParties_by_county = sorted(partySeatCountByCounty.items(), key=lambda x: x[1], reverse=True)
    # Limit the result to the top 10 parties
    for (party_name, county_name), seats in sortedParties_by_county[:10]:
        # Calculate the percentage of seats won
        percentageSeats = (seats / totalSeats) * 100
        # Calculate the total votes for the party in the county
        partyTotalVotes = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name and constituencies.query.get(vote.constituency_id).constituency_name == county_name)
        # Calculate the percentage of popular votes
        percentagePopularVotes = (partyTotalVotes / sum(vote.votes for vote in votes_data if constituencies.query.get(vote.constituency_id).constituency_name == county_name)) * 100
        # Calculate the difference percentage
        differencePercentage = abs((percentagePopularVotes - percentageSeats) / percentageSeats) * 100
        data_entry = {
            "system1": "SPR by County",
            "party": party_name,
            "county": county_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentageSeats, 2),
            "percentage_of_popular_votes": round(percentagePopularVotes, 2),
            "difference_percentage": round(differencePercentage, 2),
            "winning_party": party_name,
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
    }
        result1 = results(system1="SPR by County", 
                       party = party_name, 
                       seat_allocation = seats,
                       percentage_of_seats = round(percentageSeats, 2),
                       percentage_of_popular_votes = round(percentagePopularVotes, 2),
                       difference_percentage = round(differencePercentage, 2), 
                       winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                       different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
        result.append(data_entry)
    return result
def proportional_representation_by_region(votes_data):
    # Debugged using Phind
    # Define the total number of seats
    totalSeats = 650  # Total number of seats in the UK parliament
    # Group votes by region name and party name
    votesByRegion = defaultdict(lambda: defaultdict(list))
    for vote in votes_data:
        region_name = constituencies.query.get(vote.constituency_id).region_name
        party_name = parties.query.get(vote.party_id).party_name
        votesByRegion[region_name][party_name].append(vote)
    # Prepare the result list
    result = []
    # Calculate the seat allocation for each region
    for region_name, region_votes in votesByRegion.items():
        # Calculate the total votes for each party in the region
        regionTotalVotes = sum(vote.votes for party_votes in region_votes.values() for vote in party_votes)
        # Check if regionTotalVotes is zero to prevent division by zero
        if regionTotalVotes == 0:
            continue  # Skip this region as there are no votes
        regionSeatCount = {}
        # Calculate the seat allocation for each party in the region
        for party_name, votes in region_votes.items():
            party_votes = sum(vote.votes for vote in votes)
            # Calculate the proportion of seats this party should win
            proportion_of_seats = (party_votes / regionTotalVotes) * totalSeats
            # Allocate the seats to the party
            regionSeatCount[party_name] = round(proportion_of_seats)
        # Sort parties by the number of seats in descending order
        sortedParties = sorted(regionSeatCount.items(), key=lambda x: x[1], reverse=True)
        # Limit the result to the top parties
        for party_name, seats in sortedParties:
            # Calculate the percentage of seats won
            percentageSeats = (seats / totalSeats) * 100 if totalSeats > 0 else 1
            # Calculate the total votes for the party
            partyTotalVotes = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
            # Calculate the percentage of popular votes
            percentagePopularVotes = (partyTotalVotes / sum(vote.votes for vote in votes_data)) * 100 if sum(vote.votes for vote in votes_data) > 0 else 1
            # Calculate the difference percentage
            differencePercentage = abs((percentagePopularVotes - percentageSeats) / percentageSeats) * 100 if percentageSeats > 0 else 1
            # Create data entry for the party
            data_entry = {
                "system1": "SPR by Region",
                "region": region_name,
                "party": party_name,
                "seat_allocation": seats,
                "percentage_of_seats": round(percentageSeats, 2),
                "percentage_of_popular_votes": round(percentagePopularVotes, 2),
                "difference_percentage": round(differencePercentage, 2),
                "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
                "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
            }
            result1 = results(system1="SPR by Region", 
                             party = party_name, 
                             seat_allocation = seats,
                             percentage_of_seats = round(percentageSeats, 2),
                             percentage_of_popular_votes = round(percentagePopularVotes, 2),
                             difference_percentage = round(differencePercentage, 2), 
                             winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                             different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
            UK2019ElecDatabase.session.add(result1)
            UK2019ElecDatabase.session.commit()
            result.append(data_entry)
    # Return the result list
    return result
def proportional_representation_by_country(votes_data):
    # Define the total number of seats
    totalSeats = 650  # Total number of seats in the UK parliament
    # Group votes by country name and party name
    votesByCountry = defaultdict(lambda: defaultdict(list))
    for vote in votes_data:
        country_name = constituencies.query.get(vote.constituency_id).country_name
        party_name = parties.query.get(vote.party_id).party_name
        votesByCountry[country_name][party_name].append(vote)
    # Prepare the result list
    result = []
    # Calculate the seat allocation for each country
    for country_name, country_votes in votesByCountry.items():
        # Calculate the total votes for each party in the country
        countryTotalVotes = sum(vote.votes for party_votes in country_votes.values() for vote in party_votes)
    
        # Check if countryTotalVotes is zero to prevent division by zero
        if countryTotalVotes == 0:
            continue  # Skip this country as there are no votes
        country_seat_count = {}
        # Calculate the seat allocation for each party in the country
        for party_name, votes in country_votes.items():
            party_votes = sum(vote.votes for vote in votes)
            # Calculate the proportion of seats this party should win
            proportion_of_seats = (party_votes / countryTotalVotes) * totalSeats
            # Allocate the seats to the party
            country_seat_count[party_name] = round(proportion_of_seats)
        # Sort parties by the number of seats in descending order
        sortedParties = sorted(country_seat_count.items(), key=lambda x: x[1], reverse=True)
        # Limit the result to the top parties
        for party_name, seats in sortedParties:
            # Calculate the percentage of seats won
            percentageSeats = (seats / totalSeats) * 100 if totalSeats > 0 else 1
            # Calculate the total votes for the party
            partyTotalVotes = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
            # Calculate the percentage of popular votes
            percentagePopularVotes = (partyTotalVotes / sum(vote.votes for vote in votes_data)) * 100 if sum(vote.votes for vote in votes_data) > 0 else 1
            # Calculate the difference percentage
            differencePercentage = abs((percentagePopularVotes - percentageSeats) / percentageSeats) * 100 if percentageSeats > 0 else 1
            # Create data entry for the party
            data_entry = {
                "system1": "SPR by Country",
                "country": country_name,
                "party": party_name,
                "seat_allocation": seats,
                "percentage_of_seats": round(percentageSeats, 2),
                "percentage_of_popular_votes": round(percentagePopularVotes, 2),
                "difference_percentage": round(differencePercentage, 2),
                "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
                "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
            }
            result.append(data_entry)
            result1 = results(system1="SPR by Country", 
                             party = party_name, 
                             seat_allocation = seats,
                             percentage_of_seats = round(percentageSeats, 2),
                             percentage_of_popular_votes = round(percentagePopularVotes, 2),
                             difference_percentage = round(differencePercentage, 2), 
                             winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                             different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
            UK2019ElecDatabase.session.add(result1)
            UK2019ElecDatabase.session.commit()
    # Return the result list
    return result
def largest_remainder_by_county():
    # Debugged using Phind
    # Define total seats to 650
    totalSeats = 650
    # Initilise a dictionary to store the amount of seat eeach party gets
    partySeats = {}
    # Get all countrys and their voters from the database
    while totalSeats > 0:
        highestVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).join(constituencies).group_by(constituencies.county_name).order_by(func.sum(votes.votes).desc()).first()[0]
        highestVotesCounty = UK2019ElecDatabase.session.query(constituencies.county_name).join(votes).group_by(constituencies.county_name).order_by(func.sum(votes.votes).desc()).first()
        highestVotesCountyName = highestVotesCounty.county_name
        quota = highestVotes / (len(partySeats) + 1)

        for party in parties.query.all():
            partyVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).join(constituencies).filter(constituencies.county_name == highestVotesCountyName, votes.party_id).first()[0]
            if partyVotes >= quota and partySeats.get(parties.party_name, 0) < totalSeats:
                partySeats[party.party_name] = partySeats.get(party.party_name, 0 + 1)
                totalSeats -= 1
    result = []
    for party_name, seats in partySeats.items():
        # Calculate amount of seats that have been won
        percentSeats = (seats / totalSeats) * 100 if totalSeats > 0 else 1
        # Calculate the total votes for the party
        partyTotalVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).filter(votes.party_id == parties.query.filter_by(party_name=party_name).first().party_id).scalar()
        # Calculate the percentage of popular votes
        percentPopularVotes = (partyTotalVotes / UK2019ElecDatabase.session.query(func.sum(votes.votes)).scalar()) * 100
        # Calculate the difference pecentage
        differencePercentage = abs((percentPopularVotes - percentSeats) / percentSeats) * 100
        data_entry = {
            "system1": "Largest Remainder By County",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentSeats, 2),
            "percentage_of_popular_votes": round(percentPopularVotes, 2),
            "difference_percentage": round(differencePercentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
            }
        result.append(data_entry)
        result1 = results(system1="Largest Remainder by County", 
                          party = party_name, 
                          seat_allocation = seats,
                          percentage_of_seats = round(percentSeats, 2),
                          percentage_of_popular_votes = round(percentPopularVotes, 2),
                          difference_percentage = round(differencePercentage, 2), 
                          winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                          different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
    return result
def largest_remainder_by_region():
    # Debugged using Phind
    # Define total seats to 650
    totalSeats = 650
    # Initilise a dictionary to store the amount of seat eeach party gets
    partySeats = {}
    # Get all countrys and their voters from the database
    while totalSeats > 0:
        highestVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).join(constituencies).group_by(constituencies.region_name).order_by(func.sum(votes.votes).desc()).first()[0]
        highestVotesCounty = UK2019ElecDatabase.session.query(constituencies.region_name).join(votes).group_by(constituencies.region_name).order_by(func.sum(votes.votes).desc()).first()
        highestVotesCountyName = highestVotesCounty.region_name
        quota = highestVotes / (len(partySeats) + 1)

        for party in parties.query.all():
            partyVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).join(constituencies).filter(constituencies.region_name == highestVotesCountyName, votes.party_id).first()[0]
            if partyVotes >= quota and partySeats.get(parties.party_name, 0) < totalSeats:
                partySeats[party.party_name] = partySeats.get(party.party_name, 0 + 1)
                totalSeats -= 1
    result = []
    for party_name, seats in partySeats.items():
        # Calculate amount of seats that have been won
        percentSeats = (seats / totalSeats) * 100 if totalSeats > 0 else 1
        # Calculate the total votes for the party
        partyTotalVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).filter(votes.party_id == parties.query.filter_by(party_name=party_name).first().party_id).scalar()
        # Calculate the percentage of popular votes
        percentPopularVotes = (partyTotalVotes / UK2019ElecDatabase.session.query(func.sum(votes.votes)).scalar()) * 100
        # Calculate the difference pecentage
        differencePercentage = abs((percentPopularVotes - percentSeats) / percentSeats) * 100
        data_entry = {
            "system1": "Largest Remainder By Region",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentSeats, 2),
            "percentage_of_popular_votes": round(percentPopularVotes, 2),
            "difference_percentage": round(differencePercentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
            }
        result.append(data_entry)
        result1 = results(system1="Largest Remainder by Region", 
                          party = party_name, 
                          seat_allocation = seats,
                          percentage_of_seats = round(percentSeats, 2),
                          percentage_of_popular_votes = round(percentPopularVotes, 2),
                          difference_percentage = round(differencePercentage, 2), 
                          winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                          different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
    return result
def largest_remainder_by_country():
    # Debugged using Phind
    # Define total seats to 650
    totalSeats = 650
    # Initilise a dictionary to store the amount of seat eeach party gets
    partySeats = {}
    # Get all countrys and their voters from the database
    while totalSeats > 0:
        highestVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).join(constituencies).group_by(constituencies.country_name).order_by(func.sum(votes.votes).desc()).first()[0]
        highestVotesCountry = UK2019ElecDatabase.session.query(constituencies.country_name).join(votes).group_by(constituencies.country_name).order_by(func.sum(votes.votes).desc()).first()
        highestVotesCountryName = highestVotesCountry.country_name
        quota = highestVotes / (len(partySeats) + 1)

        for party in parties.query.all():
            partyVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).join(constituencies).filter(constituencies.country_name == highestVotesCountryName, votes.party_id).first()[0]
            if partyVotes >= quota and partySeats.get(parties.party_name, 0) < totalSeats:
                partySeats[party.party_name] = partySeats.get(party.party_name, 0 + 1)
                totalSeats -= 1
    result = []
    for party_name, seats in partySeats.items():
        # Calculate amount of seats that have been won
        percentSeats = (seats / totalSeats) * 100 if totalSeats > 0 else 1
        # Calculate the total votes for the party
        partyTotalVotes = UK2019ElecDatabase.session.query(func.sum(votes.votes)).filter(votes.party_id == parties.query.filter_by(party_name=party_name).first().party_id).scalar()
        # Calculate the percentage of popular votes
        percentPopularVotes = (partyTotalVotes / UK2019ElecDatabase.session.query(func.sum(votes.votes)).scalar()) * 100
        # Calculate the difference pecentage
        differencePercentage = abs((percentPopularVotes - percentSeats) / percentSeats) * 100
        data_entry = {
            "system1": "Largest Remainder by Country",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentSeats, 2),
            "percentage_of_popular_votes": round(percentPopularVotes, 2),
            "difference_percentage": round(differencePercentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
            }
        result.append(data_entry)
        result1 = results(system1="Largest Remainder by Country", 
                          party = party_name, 
                          seat_allocation = seats,
                          percentage_of_seats = round(percentSeats, 2),
                          percentage_of_popular_votes = round(percentPopularVotes, 2),
                          difference_percentage = round(differencePercentage, 2), 
                          winning_party = "Conservative" if party_name != "Conservative" else "Yes", 
                          different_from_actual_winner = "Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
    return result
def dhondt_by_county(votes_data):
    # Debugged using Phind
    # Initialize dictionaries to count the seats won by each party and the total votes for each party
    partySeatCount = defaultdict(int)
    partyTotalVotes = defaultdict(int)
    # Use the pre-determined seats
    seatsWon = calculate_seats_based_on_constituencies(votes_data)
    # Iterate over the pre-determined seats
    for party_name, seats in seatsWon.items():
        # Update the seat count for the party
        partySeatCount[party_name] = seats
    # Prepare the result list
    result = []
    # Calculate the total seats won by all parties
    total_seats = 650
    # Sort parties by the number of seats in descending order
    sortedParties = sorted(partySeatCount.items(), key=lambda x: x[1], reverse=True)
    # Limit the result to the top 12 parties
    for party_name, seats in sortedParties[:12]:
        # Calculate the percentage of seats won
        percentage_seats = (seats / total_seats) * 100
        # Calculate the total votes for the party
        partyTotalVotes[party_name] = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
        # Calculate the percentage of popular votes
        percentage_popular_votes = (partyTotalVotes[party_name] / sum(vote.votes for vote in votes_data)) * 100
        # Calculate the difference percentage
        difference_percentage = abs((percentage_popular_votes - percentage_seats) / percentage_seats) * 100
        data_entry = {
            "system1": "D'Hondt by County",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentage_seats, 2),
            "percentage_of_popular_votes": round(percentage_popular_votes, 2),
            "difference_percentage": round(difference_percentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
        }
        result1 = results(system1="D'Hondt by County",
                         party=party_name,
                         seat_allocation=seats,
                         percentage_of_seats=round(percentage_seats, 2),
                         percentage_of_popular_votes=round(percentage_popular_votes, 2),
                         difference_percentage=round(difference_percentage, 2),
                         winning_party="Conservative" if party_name != "Conservative" else "Yes",
                         different_from_actual_winner="Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
        result.append(data_entry)
    return result
def dhondt_by_region(votes_data):
    # Debugged using Phind
    # Initialize dictionaries to count the seats won by each party and the total votes for each party
    partySeatCount = defaultdict(int)
    partyTotalVotes = defaultdict(int)
    # Use the pre-determined seats
    seatsWon = calculate_seats_based_on_constituencies(votes_data)
    # Iterate over the pre-determined seats
    for party_name, seats in seatsWon.items():
        # Update the seat count for the party
        partySeatCount[party_name] = seats
    # Prepare the result list
    result = []
    # Calculate the total seats won by all parties
    total_seats = 650
    # Sort parties by the number of seats in descending order
    sortedParties = sorted(partySeatCount.items(), key=lambda x: x[1], reverse=True)
    # Limit the result to the top 12 parties
    for party_name, seats in sortedParties[:12]:
        # Calculate the percentage of seats won
        percentage_seats = (seats / total_seats) * 100
        # Calculate the total votes for the party
        partyTotalVotes[party_name] = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
        # Calculate the percentage of popular votes
        percentage_popular_votes = (partyTotalVotes[party_name] / sum(vote.votes for vote in votes_data)) * 100
        # Calculate the difference percentage
        difference_percentage = abs((percentage_popular_votes - percentage_seats) / percentage_seats) * 100
        data_entry = {
            "system1": "D'Hondt by Region",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentage_seats, 2),
            "percentage_of_popular_votes": round(percentage_popular_votes, 2),
            "difference_percentage": round(difference_percentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
        }
        result1 = results(system1="D'Hondt by Region",
                         party=party_name,
                         seat_allocation=seats,
                         percentage_of_seats=round(percentage_seats, 2),
                         percentage_of_popular_votes=round(percentage_popular_votes, 2),
                         difference_percentage=round(difference_percentage, 2),
                         winning_party="Conservative" if party_name != "Conservative" else "Yes",
                         different_from_actual_winner="Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
        result.append(data_entry)
    return result
def dhondt_by_country(votes_data):
    # Debugged using Phind
    # Initialize dictionaries to count the seats won by each party and the total votes for each party
    partySeatCount = defaultdict(int)
    partyTotalVotes = defaultdict(int)
    # Use the pre-determined seats
    seatsWon = calculate_seats_based_on_constituencies(votes_data)
    # Iterate over the pre-determined seats
    for party_name, seats in seatsWon.items():
        # Update the seat count for the party
        partySeatCount[party_name] = seats
    # Prepare the result list
    result = []
    # Calculate the total seats won by all parties
    total_seats = 650
    # Sort parties by the number of seats in descending order
    sortedParties = sorted(partySeatCount.items(), key=lambda x: x[1], reverse=True)
    # Limit the result to the top 12 parties
    for party_name, seats in sortedParties[:12]:
        # Calculate the percentage of seats won
        percentage_seats = (seats / total_seats) * 100
        # Calculate the total votes for the party
        partyTotalVotes[party_name] = sum(vote.votes for vote in votes_data if parties.query.get(vote.party_id).party_name == party_name)
        # Calculate the percentage of popular votes
        percentage_popular_votes = (partyTotalVotes[party_name] / sum(vote.votes for vote in votes_data)) * 100
        # Calculate the difference percentage
        difference_percentage = abs((percentage_popular_votes - percentage_seats) / percentage_seats) * 100
        data_entry = {
            "system1": "D'Hondt by Country",
            "party": party_name,
            "seat_allocation": seats,
            "percentage_of_seats": round(percentage_seats, 2),
            "percentage_of_popular_votes": round(percentage_popular_votes, 2),
            "difference_percentage": round(difference_percentage, 2),
            "winning_party": "Conservative" if party_name != "Conservative" else "Yes",
            "different_from_actual_winner": "Yes" if party_name != "Conservative" else "No"
        }
        result1 = results(system1="D'Hondt by Country",
                         party=party_name,
                         seat_allocation=seats,
                         percentage_of_seats=round(percentage_seats, 2),
                         percentage_of_popular_votes=round(percentage_popular_votes, 2),
                         difference_percentage=round(difference_percentage, 2),
                         winning_party="Conservative" if party_name != "Conservative" else "Yes",
                         different_from_actual_winner="Yes" if party_name != "Conservative" else "No")
        UK2019ElecDatabase.session.add(result1)
        UK2019ElecDatabase.session.commit()
        result.append(data_entry)
    return result